package org.dyndns.opendemogroup.optimizer.selections;

import java.util.Arrays;
import java.util.Random;

import org.dyndns.opendemogroup.optimizer.IOptimizationProblem;
import org.dyndns.opendemogroup.optimizer.ISelection;
import org.dyndns.opendemogroup.optimizer.Member;
import org.dyndns.opendemogroup.optimizer.Pair;
import org.dyndns.opendemogroup.optimizer.Population;

/**
 * Implemented as described in slide 16 of howGAsWork1.pdf.
 */
public class Tournament implements ISelection
{

	private int tournamentSize;

	private double fairnessProbability;

	private Member[] participants;

	public Tournament ( int tournamentSize, double fairnessProbability )
	{
		this.tournamentSize = tournamentSize;
		this.fairnessProbability = fairnessProbability;
		participants = new Member[tournamentSize];
	}

	/**
	 * @see ISelection#select(java.util.Random, Population,
	 *      IOptimizationProblem, int)
	 */
	public Pair<Member, Member> select ( Random randomSource,
			Population population, IOptimizationProblem problem, int loopIndex )
	{
		int populationSize = population.getPopulationSize ( );
		// { pick participants at random
		for ( int i = 0; i < tournamentSize; i++ )
		{
			int index = randomSource.nextInt ( populationSize );
			participants[i] = population.members[index];
		}
		// }

		// { let the fighting begin!
		Arrays.sort ( participants, null );
		Member childOne =
			fight ( randomSource, problem, participants, fairnessProbability,
				tournamentSize );
		Member childTwo =
			fight ( randomSource, problem, participants, fairnessProbability,
				tournamentSize );
		// }

		Pair<Member, Member> result = new Pair<Member, Member> ( );
		result.first = childOne;
		result.second = childTwo;

		return result;
	}

	static Member fight ( Random randomSource, IOptimizationProblem problem,
			Member[] participants, double fairnessProbability,
			int tournamentSize )
	{
		Member winner;
		double r = randomSource.nextDouble ( );
		if ( r < fairnessProbability )
		{
			// { pick fittest participant
			if ( problem.isMaximizing ( ) )
			{
				winner = participants[tournamentSize - 1];
			}
			else
			{
				winner = participants[0];
			}
			// }
		}
		else
		{
			// the fight wasn't fair! It was fixed from the start!!
			// pick an index into the participant pool size, minus one
			int index = randomSource.nextInt ( tournamentSize - 1 );
			// { pick a less fit participant at random
			if ( problem.isMaximizing ( ) )
			{
				// exclude the last one
				winner = participants[index];
			}
			else
			{
				// exclude the first one
				winner = participants[index + 1];
			}
			// }
		}
		return winner;
	}

	public void reset ( Random randomSource, Population population,
			IOptimizationProblem problem )
	{
		// TODO Auto-generated method stub

	}
}
